#include "kernel.h"
#include "hashtable_app.h"
#include "honeypot.h"
#include "mutex.h"
#include "atomic.h"
//#define SIZE_INIT 0x64; 
HashTable *spammer; 
HashTable *ports;
HashTable *evil;
HashTable *power; //holds the power of 33
int packet_num=0;
int byte_num=0;
int packet_per_second=0;
int bit_per_second=0;
int *packetNum=&packet_num;
int *byteNum=&byte_num;
int *packetPerSecond=&packet_per_second;
int *bitPerSecond=&bit_per_second;
int key_size=0x4;
int power_init=0x64;
unsigned short secret=0x1034;
int read_lock_s=0;
int wlock_s=0;
int *write_lock_s=&wlock_s;
int read_lock_p=0;
int wlock_p=0;
int *write_lock_p=&wlock_p;
int read_lock_e=0;
int wlock_e=0;
int *write_lock_e=&wlock_e;
/* the following are not needed any more -TO BE DELETE  
 #define ADD_SPAMMER_R 0x0101;
 #define ADD_EVIL_R 0x201;
 #define ADD_VULNERABLE_R 0x301;
 #define DEL_SPAMMER_R 0x102;
 #define DEL_EVIL_R 0x202;
 #define DEL_VULNERABLE_R 0x302;
 #define PRINT_R 0x103;
 #define POWER_INIT 0x989A68;
 
 int const add_spammer=0x1010000;
 const int add_evil=0x2010000;
 int const add_vulnerable=0x3010000;
 int const del_spammer=0x1020000;
 int const del_evil= 0x2020000;
 int const del_vulnerable= 0x3020000;
 int const print=0x1030000;*/

// method from STACKOVERFLOW:http://stackoverflow.com/questions/101439/the-most-efficient-way-to-implement-an-integer-based-power-function-powint-int
unsigned int ipow(unsigned int base, unsigned int exp)
{
  unsigned int result = 1;
	while (exp)
	{
		if (exp & 1)
			result *= base;
		exp >>= 1;
		base *= base;
	}
	
	return result;
}



void honeypot_init(void){
	printf("start spammer initiating\n");
	spammer= CreateHash(key_size);
	printf("finish spammer initiaing, start ports initiating!\n");	
    ports = CreateHash(key_size);
	evil = CreateHash(key_size);
	
	printf("start power table init\n");	
	
	power= CreateHash(key_size);
	
	printf("finish power table init\n");	
	// decrease from 3300
	for (int i=0; i < 100; i++){
		
		AddToHash(power,3300-i,ipow(33, 3300-i));
	}
}




// return 1 if the packet is a command packet; otherwise, 0
int  detm_packet (unsigned int *pkt){
	struct honeypot_command_packet *hcp=(struct honeypot_command_packet *) pkt;
	// ? what is the difference to the struct pointer and char pointer?
	// ? pkt+1 is incremented by 4 bytes or 1 byte
	
	if((hcp->secret_big_endian) == secret){
		
		//compare to determine which command it refers to
		unsigned int key=hcp->data_big_endian;
        switch(hcp->cmd_big_endian){
			case 0x00000101:{
				
				lock(write_lock_s);
				AddToHash(spammer,key,0);
				//C:
                unlock(write_lock_s);
                break;}
			case 0x00000201:{
				
				lock(write_lock_p);
				AddToHash(ports,key,0);
				unlock(write_lock_p);
                break;}
			case 0x00000301:{
				
				lock(write_lock_e);
				AddToHash(evil, key, 0);
				unlock(write_lock_e);
                break;}
			case 0x00000102:{
				
				lock(write_lock_s);
				RemoveFromHash(spammer,&key);
				unlock(write_lock_s);
                break;}
			case 0x00000202:{
				lock(write_lock_p);
				RemoveFromHash(ports,&key);
				unlock(write_lock_p);
                break;}
			case 0x00000302:{
				lock(write_lock_e);
				RemoveFromHash(evil, &key);
				unlock(write_lock_e);
				break;}
			case 0x00000103:{
				
				printf("packetNum = %n", packetNum);
				printf("byteNum = %n", byteNum);
				//printf("packetPerSecond = %n", packetPerSecond);
				//printf("bitPerSecond = %n", bitPerSecond);
				break;}
			default: {
				printf("V= %d\n",spammer->fTableSize);    
				
				break;}
		}
		return 1;
		
	}else {
//		printf("L\n");
		return 0;
	}
	
}

void compare_sv( unsigned int *hcp){
	struct honeypot_command_packet *pkt=(struct honeypot_command_packet *) hcp;
    struct packet_header ph= (struct packet_header)(pkt -> headers);
	unsigned int *source= &ph.ip_source_address_big_endian;      //pkt[12] << 24 | pkt[13] << 16 | pkt[14] << 8| pkt[15]; 
	unsigned int *dest= &ph.ip_dest_address_big_endian;                   //pkt[16] << 24 | pkt[17] << 16 | pkt[18] << 8| pkt[19]; 
	lock(write_lock_s);
	hs_entry *item=  HashLookup(spammer, source);
	
	unlock(write_lock_s);
	
	if (item != NULL)  atomic_incr((int* )&(item->val),1); 
	
    lock(write_lock_p);
	
	item=HashLookup(ports, dest);
	
    unlock(write_lock_p);
	
	if (item != NULL)  atomic_incr((int*)&(item->val),1);	
}

//start from 0.
void div_evil(unsigned int *hcp, int n){
	// the following is the djb hash
	//we have 7 cores for evil computing
	// how to
	//unsigned int n= hcp->headers->ip_len;
	unsigned char *pkt=(unsigned char* ) hcp;
	unsigned int hash = 5381;;
	//	printf("%d\n",n);	
	int i = 0;
	while (i < n-8) {
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
		hash = hash * 33 + pkt[i++];
	}
	while (i < n)
		hash = hash * 33 + pkt[i++];
	//return hash;
   
	lock(write_lock_e);
	hs_entry *item=  HashLookup(evil,(unsigned int* )(&hash));
	
unlock(write_lock_e);
	if (item != NULL)  atomic_incr((int* )&(item->val),1); 
}



//helper find power

unsigned int inline calc_power(int n){
	hs_entry *item=HashLookup(power,(unsigned int* )&n);
	if (item != NULL){
		return item->val;
	}else{
		return ipow(33, n);
	}
}

void merge_compare_evil(unsigned int h1, unsigned int n1, unsigned int h2, unsigned int n2, unsigned int h3, unsigned int n3, unsigned int* pkt){
	// h1 is the biggest
	unsigned int merge= 5381*ipow(33,(n1+n2+n3))+h1*ipow(33,(n2+n3))+ h2*ipow(33,n3)+h3;
	lock(write_lock_e);
    //unsigned int compare=div_evil(pkt, n1+n2+n3-1);
    //printf("merge: %d\n", n1+n2+n3);
    //printf("compare: %x\n", compare);   
	hs_entry *item=  HashLookup(evil,(unsigned int* )(&merge));
	unlock(write_lock_e);
	if (item != NULL)  atomic_incr((int* )&(item->val),1); 
	
}



// parameter n: the number of bytes

void global_incr (int n){
	atomic_incr(packetNum,1);
	atomic_incr(byteNum, n);
//	printf("G=%d", *packetNum);
	//TO-DO: per second data to do.
}

void global_print(void){
printf_i("\nspammer: %d\n", spammer->fNumEntries);
printf_i("ports: %d\n", ports ->fNumEntries);
/*for(int i=0; i<evil->fNumEntries; i++){
if (evil->fTable != NULL && evil->fTable[i] != NULL){
printf("evil: %d", i);
printf("evil val: %d\n",evil->fTable[i]->val);
}
}*/
printf_i("evil: %d\n", evil->fNumEntries);
printf_i("num: %d\n", *packetNum);
printf_i("numb: %d\n", *byteNum);
}

int get_packets_num (void){
return *packetNum;
}
